﻿Option Explicit On
Option Strict On

Imports System.Reflection

Friend Class ExceptionFormatter

#Region " Constants "

    Private Const RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED As String = "*** Permission Denied ***"
    Private Const RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION As String = "Information could not be accessed."

#End Region

#Region " Shared Methods "

    ''' <summary>
    ''' Returns a GUID uniquely identfying a crash
    ''' </summary>
    ''' <param name="Ex"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function GetCrashHash(ByVal Ex As Exception) As String
        Dim ExceptionMessage As String = ""
        Dim StackTraceConcat As String = ""

        Dim CurrentEx As Exception = Ex

        While CurrentEx IsNot Nothing
            StackTraceConcat &= Ex.StackTrace
            ExceptionMessage = Ex.Message

            CurrentEx = CurrentEx.InnerException
        End While

        'Generate a unique crash key = exception + stack trace
        'then convert crash key to a hash (used to identify unique crashes)
        Dim CrashKey As String = ExceptionMessage & StackTraceConcat
        Dim CrashHash As String

        Using MD5 As New System.Security.Cryptography.MD5CryptoServiceProvider()
            Dim byteHash() As Byte = MD5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(CrashKey))
            CrashHash = Convert.ToBase64String(byteHash)
        End Using

        Return CrashHash
    End Function

    Private Shared Function CollectionToHtmlTable(ByVal Collection As Generic.Dictionary(Of String, String)) As String

        Dim TD As String
        Dim MyHTML As String

        TD = "<td><FONT face=""Arial"" size=""2""><!--VALUE--></FONT></TD>"
        MyHTML = "<table width=""100%"">" & _
        " <TR bgcolor=""#C0C0C0"">" & _
        TD.Replace("<!--VALUE-->", " <B>Name</B>") & _
        " " & TD.Replace("<!--VALUE-->", " <B>Value</B>") & "</tr>"
        'No Body? -> N/A
        If (Collection.Count <= 0) Then
            Collection = New Generic.Dictionary(Of String, String)
            Collection.Add("N/A", "")
        Else
            'Table Body
            For Each item As Generic.KeyValuePair(Of String, String) In Collection
                MyHTML += "<TR valign=""top"" bgcolor=""#EEEEEE"">" & _
                TD.Replace("<!--VALUE-->", item.Key.ToString) & " "
                If item.Value Is Nothing Then
                    MyHTML &= TD.Replace("<!--VALUE-->", "Unknown") & "</tr> "
                Else
                    MyHTML &= TD.Replace("<!--VALUE-->", item.Value.ToString) & "</tr> "
                End If
            Next
        End If
        'Table Footer
        Return MyHTML & "</table>"

    End Function

    Private Shared Function CollectionToPlainTextTable(ByVal Collection As Generic.Dictionary(Of String, String)) As String

        Dim MyHTML As String

        MyHTML = ""
        'No Body? -> N/A
        If (Collection.Count <= 0) Then
            Collection = New Generic.Dictionary(Of String, String)
            Collection.Add("N/A", "")
        Else
            'Table Body
            For Each item As Generic.KeyValuePair(Of String, String) In Collection
                If item.Value Is Nothing Then
                    MyHTML += item.Key & " : * Unknown *" & vbCrLf
                Else
                    MyHTML += item.Key & " : " & item.Value & vbCrLf
                End If
            Next
        End If
        'Table Footer
        Return MyHTML

    End Function

    Private Shared Function CleanHTML(ByVal HTML As String) As String

        If HTML Is Nothing Then
            HTML = ""
        End If

        HTML = System.Web.HttpUtility.HtmlEncode(HTML)

        If HTML.Length <> 0 Then
            HTML = HTML.Replace("<", "<").Replace("\r\n", "<br />").Replace("&", "&").Replace(" ", " ")
        Else
            HTML = ""
        End If
        Return HTML

    End Function

#End Region

#Region " Public Methods "

    Public Function GetHTMLError(ByVal Ex As Exception, ByVal SystemName As String, ByVal VersionNumber As String) As String

        Dim Heading As String
        Dim MyHTML As String
        Dim System_Info As New Generic.Dictionary(Of String, String)
        Dim m_data As String

        'Date
        System_Info.Add("Date Generated", CleanHTML(Now.ToLongDateString & " " & Now.ToLongTimeString))

        'Crash Hash
        System_Info.Add("Crash Hash", GetCrashHash(Ex))

        'Version Number
        Try
            m_data = VersionNumber
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("System Version", CleanHTML(VersionNumber))

        'Environment
        Try
            m_data = Environment.MachineName
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Machine Name", CleanHTML(m_data))

        Try
            m_data = Environment.OSVersion.ToString()
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("OS Platform", CleanHTML(m_data))

        Try
            m_data = Environment.CommandLine.ToString()
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Command Line", CleanHTML(m_data))

        Try
            m_data = Environment.CurrentDirectory.ToString()
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Current Directory", CleanHTML(m_data))

        Try
            m_data = Environment.ExitCode.ToString()
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Process Exit Code", CleanHTML(m_data))

        Try
            m_data = Environment.HasShutdownStarted.ToString()
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Has Shutdown Started", CleanHTML(m_data))

        Try
            m_data = Environment.SystemDirectory
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("System Directory", CleanHTML(m_data))

        Try
            m_data = Environment.TickCount.ToString()
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("System Tick Count", CleanHTML(m_data))

        Try
            m_data = Environment.UserDomainName.ToString()
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Network Domain Name", CleanHTML(m_data))

        Try
            m_data = Environment.UserInteractive.ToString()
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Is User Interactive", CleanHTML(m_data))

        Try
            m_data = Environment.UserName.ToString()
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("User Name", CleanHTML(m_data))

        Try
            m_data = Environment.Version.ToString()
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Version", CleanHTML(m_data))

        Try
            m_data = Environment.WorkingSet.ToString()
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Working Set", CleanHTML(m_data))

        'Thread Info
        Dim m_threadIdentity As String
        Try
            m_threadIdentity = System.Threading.Thread.CurrentPrincipal.Identity.Name
        Catch e As System.Security.SecurityException
            m_threadIdentity = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_threadIdentity = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Thread Identity", CleanHTML(m_threadIdentity))

        Try
            m_data = System.Threading.Thread.CurrentPrincipal.Identity.IsAuthenticated.ToString()
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Thread Identity Is Authenticated", CleanHTML(m_data))

        Try
            m_data = System.Threading.Thread.CurrentThread.Name
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Thread Name", CleanHTML(m_data))

        'Windows Identity
        Dim m_windowsIdentity As String
        Try
            m_windowsIdentity = System.Security.Principal.WindowsIdentity.GetCurrent().Name
        Catch e As System.Security.SecurityException
            m_windowsIdentity = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_windowsIdentity = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Windows Identity", CleanHTML(m_windowsIdentity))

        Dim m_windowsIdentityAuthenticationType As String
        Try
            m_windowsIdentityAuthenticationType = System.Security.Principal.WindowsIdentity.GetCurrent().AuthenticationType
        Catch e As System.Security.SecurityException
            m_windowsIdentityAuthenticationType = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_windowsIdentityAuthenticationType = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Windows Identity Authentication Type", CleanHTML(m_windowsIdentityAuthenticationType))

        Try
            m_data = System.Security.Principal.WindowsIdentity.GetCurrent().IsAnonymous.ToString
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Windows Identity Is Anonymous", CleanHTML(m_data))

        Try
            m_data = System.Security.Principal.WindowsIdentity.GetCurrent().IsAuthenticated.ToString
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Windows Identity Is Authenticated", CleanHTML(m_data))

        Try
            m_data = System.Security.Principal.WindowsIdentity.GetCurrent().IsGuest.ToString
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Windows Identity Is Guest", CleanHTML(m_data))

        Try
            m_data = System.Security.Principal.WindowsIdentity.GetCurrent().IsSystem.ToString
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Windows Identity Is System", CleanHTML(m_data))

        'App Domain
        Dim m_appDomainName As String
        Try
            m_appDomainName = AppDomain.CurrentDomain.FriendlyName
        Catch e As System.Security.SecurityException
            m_appDomainName = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_appDomainName = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("App Domain Name", CleanHTML(m_appDomainName))


        Heading = "<table BORDER=""0"" WIDTH=""100%"" cellpadding=""1"" cellspacing=""0""><tr><td bgcolor=""black"" COLSPAN=""2""><FONT face=""Arial"" color=""white""><B> <!--HEADER--></B></FONT></TD></tr></table>"

        MyHTML = "<FONT face=""Arial"" size=""5"" color=""red"">" & SystemName & " - Experienced an unhandled error</FONT><br /><br/>"

        MyHTML &= "<br /><br />" & Heading.Replace("<!--HEADER-->", "System Information")
        MyHTML &= CollectionToHtmlTable(System_Info)

        'System Stack Trace
        Try
            m_data = Environment.StackTrace
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Clear()
        System_Info.Add("System Stack Trace", CleanHTML(m_data))
        MyHTML += "<br/>"
        MyHTML += Heading.Replace("<!--HEADER-->", "System Stack Trace")
        MyHTML += CollectionToHtmlTable(System_Info)

        MyHTML &= GetExceptionHTML(Ex, 1)

        Return MyHTML

    End Function

    Public Function GetPlainTextError(ByVal Ex As Exception, ByVal SystemName As String, ByVal VersionNumber As String) As String

        Dim MyHTML As String
        Dim System_Info As New Generic.Dictionary(Of String, String)
        Dim m_data As String

        'Date
        System_Info.Add("Date Generated", Now.ToLongDateString & " " & Now.ToLongTimeString)

        'Crash Hash
        System_Info.Add("Crash Hash", GetCrashHash(Ex))

        'Version Number
        Try
            m_data = VersionNumber
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("System Version", VersionNumber)

        'Environment
        Try
            m_data = Environment.MachineName
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Machine Name", m_data)

        Try
            m_data = Environment.OSVersion.ToString()
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("OS Platform", m_data)

        Try
            m_data = Environment.CommandLine.ToString()
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Command Line", m_data)

        Try
            m_data = Environment.CurrentDirectory.ToString()
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Current Directory", m_data)

        Try
            m_data = Environment.ExitCode.ToString()
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Process Exit Code", m_data)

        Try
            m_data = Environment.HasShutdownStarted.ToString()
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Has Shutdown Started", m_data)

        Try
            m_data = Environment.SystemDirectory
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("System Directory", m_data)

        Try
            m_data = Environment.TickCount.ToString()
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("System Tick Count", m_data)

        Try
            m_data = Environment.UserDomainName.ToString()
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Network Domain Name", m_data)

        Try
            m_data = Environment.UserInteractive.ToString()
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Is User Interactive", m_data)

        Try
            m_data = Environment.UserName.ToString()
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("User Name", m_data)

        Try
            m_data = Environment.Version.ToString()
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Version", m_data)

        Try
            m_data = Environment.WorkingSet.ToString()
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Working Set", m_data)

        'Thread Info
        Dim m_threadIdentity As String
        Try
            m_threadIdentity = System.Threading.Thread.CurrentPrincipal.Identity.Name
        Catch e As System.Security.SecurityException
            m_threadIdentity = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_threadIdentity = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Thread Identity", m_threadIdentity)

        Try
            m_data = System.Threading.Thread.CurrentPrincipal.Identity.IsAuthenticated.ToString()
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Thread Identity Is Authenticated", m_data)

        Try
            m_data = System.Threading.Thread.CurrentThread.Name
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Thread Name", m_data)

        'Windows Identity
        Dim m_windowsIdentity As String
        Try
            m_windowsIdentity = System.Security.Principal.WindowsIdentity.GetCurrent().Name
        Catch e As System.Security.SecurityException
            m_windowsIdentity = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_windowsIdentity = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Windows Identity", m_windowsIdentity)

        Dim m_windowsIdentityAuthenticationType As String
        Try
            m_windowsIdentityAuthenticationType = System.Security.Principal.WindowsIdentity.GetCurrent().AuthenticationType
        Catch e As System.Security.SecurityException
            m_windowsIdentityAuthenticationType = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_windowsIdentityAuthenticationType = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Windows Identity Authentication Type", m_windowsIdentityAuthenticationType)

        Try
            m_data = System.Security.Principal.WindowsIdentity.GetCurrent().IsAnonymous.ToString
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Windows Identity Is Anonymous", m_data)

        Try
            m_data = System.Security.Principal.WindowsIdentity.GetCurrent().IsAuthenticated.ToString
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Windows Identity Is Authenticated", m_data)

        Try
            m_data = System.Security.Principal.WindowsIdentity.GetCurrent().IsGuest.ToString
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Windows Identity Is Guest", m_data)

        Try
            m_data = System.Security.Principal.WindowsIdentity.GetCurrent().IsSystem.ToString
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("Windows Identity Is System", m_data)

        'App Domain
        Dim m_appDomainName As String
        Try
            m_appDomainName = AppDomain.CurrentDomain.FriendlyName
        Catch e As System.Security.SecurityException
            m_appDomainName = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_appDomainName = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Add("App Domain Name", m_appDomainName)


        MyHTML = SystemName & " - Experienced an unhandled error" & vbCrLf

        MyHTML &= "System Information" & vbCrLf
        MyHTML &= CollectionToPlainTextTable(System_Info)

        'System Stack Trace
        Try
            m_data = Environment.StackTrace
        Catch e As System.Security.SecurityException
            m_data = RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED
        Catch
            m_data = RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION
        End Try
        System_Info.Clear()
        System_Info.Add("System Stack Trace", m_data)
        MyHTML += vbCrLf
        MyHTML += CollectionToPlainTextTable(System_Info)

        MyHTML &= GetExceptionPlainText(Ex, 1)

        Return MyHTML

    End Function

#End Region

#Region " Private Methods "

    Private Function GetExceptionHTML(ByVal Ex As Exception, ByVal ExceptionNumber As Integer) As String

        'Returns HTML an formatted error message
        Dim Heading As String
        Dim MyHTML As String

        Dim Error_Info As New Generic.Dictionary(Of String, String)

        MyHTML = "<br/><br/><table BORDER=""0"" WIDTH=""100%"" cellpadding=""1"" cellspacing=""0""><tr><td bgcolor=""red"" COLSPAN=""2""><FONT face=""Arial"" color=""black""><B> " & " Exception Tree Level (" & ExceptionNumber.ToString & ") " & " </B></FONT></TD></tr></table><br/>"
        Heading = "<table BORDER=""0"" WIDTH=""100%"" cellpadding=""1"" cellspacing=""0""><tr><td bgcolor=""black"" COLSPAN=""2""><FONT face=""Arial"" color=""white""><B> <!--HEADER--></B></FONT></TD></tr></table>"
        MyHTML &= "<FONT face=""Arial"" size=""4"" color=""orange"">Error - " & Ex.Message & "</FONT><br /><br />"

        Error_Info.Add("Exception Type", CleanHTML(Ex.GetType().FullName))

        ' Loop through the public properties of the exception object and record their value.
        Dim aryPublicProperties As PropertyInfo()
        aryPublicProperties = Ex.GetType().GetProperties()  '
        Dim currentAdditionalInfo As Specialized.NameValueCollection
        Dim p As PropertyInfo
        Dim k As Integer
        Dim j As Integer

        For Each p In aryPublicProperties
            ' Do not log information for the InnerException or StackTrace. This information is 
            ' captured later in the process.
            If p.Name <> "InnerException" And p.Name <> "StackTrace" Then
                If p.GetValue(Ex, Nothing) Is Nothing Then
                    Error_Info.Add(p.Name, CleanHTML(""))
                Else
                    ' Loop through the collection of AdditionalInformation if the exception type is a BaseApplicationException.
                    If p.Name = "AdditionalInformation" Then
                        ' Verify the collection is not null.
                        If Not (p.GetValue(Ex, Nothing) Is Nothing) Then
                            ' Cast the collection into a local variable.
                            currentAdditionalInfo = CType(p.GetValue(Ex, Nothing), Specialized.NameValueCollection)

                            ' Check if the collection contains values.
                            If currentAdditionalInfo.Count > 0 Then
                                ' Loop through the collection adding the information to the string builder.
                                k = currentAdditionalInfo.Count - 1
                                For j = 0 To k
                                    Error_Info.Add(currentAdditionalInfo.GetKey(j), CleanHTML(currentAdditionalInfo(j)))
                                Next
                            End If
                        End If
                        ' Otherwise just write the ToString() value of the property.
                    Else

                        Error_Info.Add(p.Name, CleanHTML(p.GetValue(Ex, Nothing).ToString))

                    End If
                End If
            End If
        Next p

        MyHTML += Heading.Replace("<!--HEADER-->", "Exception Information")
        MyHTML += CollectionToHtmlTable(Error_Info)

        If Not Ex.Data Is Nothing Then
            MyHTML += "<br/>"
            MyHTML += Heading.Replace("<!--HEADER-->", "Exception Data")

            Error_Info.Clear()

            For Each Item As DictionaryEntry In Ex.Data
                Error_Info.Add(Item.Key.ToString, CleanHTML(Item.Value.ToString()))
            Next

            MyHTML += CollectionToHtmlTable(Error_Info)
        End If

        If Not Ex.StackTrace Is Nothing Then
            Error_Info.Clear()
            Error_Info.Add("StackTrace", CleanHTML(Ex.StackTrace))

            MyHTML += "<br/>"
            MyHTML += Heading.Replace("<!--HEADER-->", "Stack Trace")
            MyHTML += CollectionToHtmlTable(Error_Info)
        End If

        If Not Ex.InnerException Is Nothing Then
            MyHTML &= GetExceptionHTML(Ex.InnerException, ExceptionNumber + 1)
        End If

        Return MyHTML

    End Function

    Private Function GetExceptionPlainText(ByVal Ex As Exception, ByVal ExceptionNumber As Integer) As String

        'Returns HTML an formatted error message
        Dim MyHTML As String

        Dim Error_Info As New Generic.Dictionary(Of String, String)

        MyHTML = " Exception Tree Level (" & ExceptionNumber.ToString & ")" & vbCrLf
        MyHTML &= "Error - " & Ex.Message & vbCrLf

        Error_Info.Add("Exception Type", Ex.GetType().FullName)

        ' Loop through the public properties of the exception object and record their value.
        Dim aryPublicProperties As PropertyInfo()
        aryPublicProperties = Ex.GetType().GetProperties()  '
        Dim currentAdditionalInfo As Specialized.NameValueCollection
        Dim p As PropertyInfo
        Dim k As Integer
        Dim j As Integer

        For Each p In aryPublicProperties
            ' Do not log information for the InnerException or StackTrace. This information is 
            ' captured later in the process.
            If p.Name <> "InnerException" And p.Name <> "StackTrace" Then
                If p.GetValue(Ex, Nothing) Is Nothing Then
                    Error_Info.Add(p.Name, "")
                Else
                    ' Loop through the collection of AdditionalInformation if the exception type is a BaseApplicationException.
                    If p.Name = "AdditionalInformation" Then
                        ' Verify the collection is not null.
                        If Not (p.GetValue(Ex, Nothing) Is Nothing) Then
                            ' Cast the collection into a local variable.
                            currentAdditionalInfo = CType(p.GetValue(Ex, Nothing), Specialized.NameValueCollection)

                            ' Check if the collection contains values.
                            If currentAdditionalInfo.Count > 0 Then
                                ' Loop through the collection adding the information to the string builder.
                                k = currentAdditionalInfo.Count - 1
                                For j = 0 To k
                                    Error_Info.Add(currentAdditionalInfo.GetKey(j), currentAdditionalInfo(j))
                                Next
                            End If
                        End If
                        ' Otherwise just write the ToString() value of the property.
                    Else

                        Error_Info.Add(p.Name, p.GetValue(Ex, Nothing).ToString)

                    End If
                End If
            End If
        Next p

        MyHTML += "Exception Information" & vbCrLf
        MyHTML += CollectionToPlainTextTable(Error_Info)

        If Not Ex.Data Is Nothing Then
            MyHTML += "Exception Data"

            Error_Info.Clear()

            For Each Item As DictionaryEntry In Ex.Data
                Error_Info.Add(Item.Key.ToString, Item.Value.ToString())
            Next

            MyHTML += CollectionToPlainTextTable(Error_Info)
        End If

        If Not Ex.StackTrace Is Nothing Then
            Error_Info.Clear()
            Error_Info.Add("StackTrace", Ex.StackTrace)

            MyHTML += vbCrLf
            MyHTML += "Stack Trace"
            MyHTML += CollectionToPlainTextTable(Error_Info)
        End If

        If Not Ex.InnerException Is Nothing Then
            MyHTML &= GetExceptionPlainText(Ex.InnerException, ExceptionNumber + 1)
        End If

        Return MyHTML

    End Function

#End Region

End Class
